

//TODO: Figure out how to make an options dialog
//TODO: Add option to start minimized?


#include <Windows.h>
#include <WinReg.h>
#include <tchar.h>
#include "iTunesVisualAPI.h"


#if TARGET_OS_MAC
#error Can't build for Mac! Plugin is Windows only.
#endif



#define	MAIN iTunesPluginMain
#define IMPEXP	__declspec(dllexport)

#define kTVisualPluginName              "\016CD Art Autorun"
#define	kTVisualPluginCreator			'hook'

#define	kTVisualPluginMajorVersion		1
#define	kTVisualPluginMinorVersion		1
#define	kTVisualPluginReleaseStage		betaStage
#define	kTVisualPluginNonFinalRelease	0

#define RegReadBufferSize		1024

//#define SILENT_ERRORS

#ifdef SILENT_ERRORS
#define ShowError(msg)	
#else
#define ShowError(msg)	MessageBox(NULL, _T(msg), _T("CD Art Display Autorun"), MB_OK | MB_ICONERROR)
#endif


struct PluginData {
	void*			appCookie;
	ITAppProcPtr	appProc;

	Boolean			disabled;
};
typedef struct PluginData PluginData;


/*
	MyMemClear
*/
static void MyMemClear(LogicalAddress dest, SInt32 length)
{
	register unsigned char *ptr;

	ptr = (unsigned char*)dest;
	
	while (length-- > 0)
		*ptr++ = 0;
}

/*
	RunCAD
	starts CD Art Display if it is not already running
*/
static OSStatus RunCAD(void)
{
	OSStatus status = noErr;
	HKEY keyHandle;
	HWND cadWindow;

	// If CAD is not running, start it
	cadWindow = FindWindow(NULL, _T("CD Art Display 1.x Class"));
	if (cadWindow)
		return noErr;

	if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\CD Art Display", 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS)
	{
		// Get CAD's location from HKCU\Software\CD Art Display\ 
		BOOL result;
		DWORD type;
		char location[RegReadBufferSize];
		DWORD size = RegReadBufferSize - 1;
		STARTUPINFO si;
		PROCESS_INFORMATION pi;

		RegQueryValueEx(keyHandle, NULL, NULL, &type, (LPBYTE)location, &size);

		if (type != REG_SZ)
		{
			ShowError("Could not read \"HKCU\\Software\\CD Art Display\". Value is undefined or type is not REG_SZ.");
			return openErr;
		}

		// Run CAD 
		SecureZeroMemory(&si, sizeof(STARTUPINFO));
		SecureZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
		si.cb = sizeof(si);
		//si.dwFlags = STARTF_USESHOWWINDOW;
		//si.wShowWindow = SW_SHOWMINNOACTIVE;

		result = CreateProcess(
			location, 
			NULL, 
			NULL, 
			NULL, 
			false, 
			0, 
			NULL, 
			NULL,
			&si, 
			&pi
		);
	
		if (!result)
		{
			ShowError("Unable to launch CD Art Display.\nIs \"HKCU\\Software\\CD Art Display\" correct?");
			status = openErr;
		}

		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
	else
	{
		ShowError("Unable to determine the location of CD Art Display.\n\"HKCU\\Software\\CD Art Display\" is missing or empty.");
		status = readErr;
	}
		
	return status;
}





/*
	VisualPluginHandler
*/
static OSStatus VisualPluginHandler(OSType message, VisualPluginMessageInfo *messageInfo, void *refCon)
{
	OSStatus status;
	UInt32 size;
	PluginData* pluginData;
	pluginData = (PluginData*) refCon;

	status = noErr;

	switch (message)
	{
	case kVisualPluginInitMessage:
		// Initialize plugin data
		pluginData = (PluginData*) calloc(1, sizeof(PluginData));
		if (pluginData == NULL)
		{
			status = memFullErr;
			break;
		}

		pluginData->appCookie = messageInfo->u.initMessage.appCookie;
		pluginData->appProc = messageInfo->u.initMessage.appProc;
		pluginData->disabled = false;

		// Get disabled setting
		PlayerGetPluginNamedData(
			pluginData->appCookie, pluginData->appProc,
			"disabled",
			(void*)&pluginData->disabled,
			sizeof(pluginData->disabled),
			&size
		);

		// If not disabled, run CAD
		if (!pluginData->disabled)
			RunCAD();

		messageInfo->u.initMessage.refCon = (void*) pluginData;
		break;

	case kVisualPluginCleanupMessage:
		if (pluginData != NULL)
			free(pluginData);
		break;

	case kVisualPluginConfigureMessage:
		{
			// Ask whether CAD Autorun should be enabled/disabled
			LPCSTR text;
			int result;

			if (pluginData->disabled)
				text = _T("CD Art Display Autorun is disabled.\nLaunch CD Art Display when iTunes starts?");
			else
				text = _T("CD Art Display Autorun is enabled.\nLaunch CD Art Display when iTunes starts?");

			result = MessageBox(
				NULL,
				text,
				_T("CAD Autorun Options"),
				MB_YESNOCANCEL
			);


			// If not cancelled, save the result
			if (result == IDCANCEL)
				break;
			pluginData->disabled = result != IDYES;
			
			status = PlayerSetPluginNamedData(
				pluginData->appCookie, pluginData->appProc,
				"disabled",
				(void*)&pluginData->disabled,
				sizeof(pluginData->disabled)
			);

			if (status != noErr)
				ShowError("Could not save enabled/disabled setting.");
		}
		break;

	}

	return status;
}

/*
	RegisterVisualPlugin
*/
static OSStatus RegisterVisualPlugin(PluginMessageInfo *messageInfo)
{
	OSStatus			status;
	PlayerMessageInfo	playerMessageInfo;
	Str255				pluginName = kTVisualPluginName;
		
	MyMemClear(&playerMessageInfo.u.registerVisualPluginMessage,sizeof(playerMessageInfo.u.registerVisualPluginMessage));
	
	memcpy(&playerMessageInfo.u.registerVisualPluginMessage.name[0], &pluginName[0], pluginName[0] + 1);				

	SetNumVersion(&playerMessageInfo.u.registerVisualPluginMessage.pluginVersion,kTVisualPluginMajorVersion,kTVisualPluginMinorVersion,kTVisualPluginReleaseStage,kTVisualPluginNonFinalRelease);

	playerMessageInfo.u.registerVisualPluginMessage.options					= kVisualWantsConfigure;
	playerMessageInfo.u.registerVisualPluginMessage.handler					= (VisualPluginProcPtr)VisualPluginHandler;
	playerMessageInfo.u.registerVisualPluginMessage.registerRefCon			= 0;
	playerMessageInfo.u.registerVisualPluginMessage.creator					= kTVisualPluginCreator;
	
	playerMessageInfo.u.registerVisualPluginMessage.timeBetweenDataInMS		= 1000; // 16 milliseconds = 1 Tick,0xFFFFFFFF = Often as possible.
	playerMessageInfo.u.registerVisualPluginMessage.numWaveformChannels		= 2;
	playerMessageInfo.u.registerVisualPluginMessage.numSpectrumChannels		= 2;
	
	playerMessageInfo.u.registerVisualPluginMessage.minWidth				= 64;
	playerMessageInfo.u.registerVisualPluginMessage.minHeight				= 64;
	playerMessageInfo.u.registerVisualPluginMessage.maxWidth				= 32767;
	playerMessageInfo.u.registerVisualPluginMessage.maxHeight				= 32767;
	playerMessageInfo.u.registerVisualPluginMessage.minFullScreenBitDepth	= 0;
	playerMessageInfo.u.registerVisualPluginMessage.maxFullScreenBitDepth	= 0;
	playerMessageInfo.u.registerVisualPluginMessage.windowAlignmentInBytes	= 0;
	
	status = PlayerRegisterVisualPlugin(messageInfo->u.initMessage.appCookie,messageInfo->u.initMessage.appProc,&playerMessageInfo);
		
	return status;
	
}




//########################################
//	main entrypoint
//########################################


IMPEXP OSStatus MAIN(OSType message, PluginMessageInfo *messageInfo, void *refCon)
{
	OSStatus status;
	(void) refCon;
	
	switch (message)
	{
		case kPluginInitMessage:
			status = RegisterVisualPlugin(messageInfo);
			break;

		case kPluginCleanupMessage:
			status = noErr;
			break;
			
		default:
			status = unimpErr;
			break;
	}
	
	return status;
}
